﻿using System;
using System.Reflection;
using System.Configuration;
using System.Globalization;
using System.Collections.Generic;
using System.Drawing;

using SBPweb.Forge.Modules.Resources;
using SBPweb.Forge.Modules.Smartparts;

using SBPweb.Forge.Contracts.Components;

namespace SBPweb.Forge.Modules.Modularity
{
    /// <summary>
    /// Base Class of Modules. It implements basic functionality of IModule
    /// </summary>
    public abstract class ModuleBase : InitializableBase, IModule
    {

        #region Protected fields

		/// <summary>
		/// ServiceDictionary pGlobalServices
		/// </summary>
		private ServiceDictionary globalServices;
		/// <summary>
		/// SessionDictionary pGlobalSession
		/// </summary>
		private SessionDictionary globalSession;
		/// <summary>
		/// string pAsmPath
		/// </summary>
		private string asmPath;
		/// <summary>
        /// IModuleHost pHost
        /// </summary>
        protected IModuleHost host;
        /// <summary>
        /// ModuleHostType pHostType
        /// </summary>
        protected ModuleHostType hostType;
        /// <summary>
        /// ResourceHandler pResources
        /// </summary>
        protected ResourceHandler resources;
        /// <summary>
        /// string pName
        /// </summary>
        protected string name;
        /// <summary>
        /// string pTypeName
        /// </summary>
		protected string typeName;
        ///// <summary>
        ///// bool pIsInitialized
        ///// </summary>
        //protected bool isInitialized = false;
        /// <summary>
        /// bool pIsVisible
        /// </summary>
        protected bool isVisible = false;
        /// <summary>
        /// bool pIsEnabled
        /// </summary>
        protected bool isEnabled = false;
        /// <summary>
        /// System.Version pVersion
        /// </summary>
        protected System.Version version;
        /// <summary>
        /// System.Version pFileVersion
        /// </summary>
        protected System.Version asmVersion;
        /// <summary>
        /// Icon pIcon
        /// </summary>
        protected Icon icon;
        /// <summary>
        /// bool pAsyncLoad
        /// </summary>
		protected bool isAsyncLoad = false;
		/// <summary>
		/// bool pAllowUnload
		/// </summary>
        protected ApplicationSettingsBase settings;
		/// <summary>
		/// ModuleProfile pModuleProfile
		/// </summary>
		protected ModuleProfile moduleProfile;
		/// <summary>
		/// IPersistable pParentPersistable
		/// </summary>
		protected IPersistable parentPersistable;
		/// <summary>
		/// System.Configuration.Configuration pConfiguration
		/// </summary>
		protected System.Configuration.Configuration configuration;

        #endregion

        #region Constructor logic

		/// <summary>
		/// Constructor of ModuleBase
		/// </summary>
		/// <param name="host"></param>
		public ModuleBase(IModuleHost host)
		{
			this.host = host;
            this.parentPersistable = null;
            this.hostType = host.HostType;
            this.resources = new ResourceHandler(this.GetType(), new List<CultureInfo>(Host.SupportedCultures));

			Assembly asm = Assembly.GetAssembly(this.GetType());
            AssemblyName asmName = asm.GetName();
            string version = ResourceHandler.GetAssemblyCustomAttribute<AssemblyFileVersionAttribute>(asm) as string;

            this.configuration = null;

			this.version = new System.Version(version);
            this.asmVersion = asmName.Version;
            this.globalServices = Host.ModuleLoader.Services;
            this.globalSession = Host.ModuleLoader.Session;
            this.isAsyncLoad = false;
            this.asmPath = asm.Location;
            InitializeConfiguration(asm);
        }

        #endregion

        #region Property accessors

        /// <summary>
        /// ModuleHost instance
        /// </summary>
        public IModuleHost Host
        {
            get
            {
                return host;
            }
        }

        /// <summary>
        /// Type of the ModuleHost
        /// </summary>
        public ModuleHostType HostType
        {
            get
            {
                return hostType;
            }
        }

        /// <summary>
        /// Services
        /// </summary>
        public ServiceDictionary Services
        {
            get
            {
                return globalServices;
            }
            internal set
            {
                globalServices = value;
            }
        }

		/// <summary>
		/// Session
		/// </summary>
		public SessionDictionary Session
		{
			get
			{
				return globalSession;
			}
			internal set
			{
				globalSession = value;
			}
		}

        /// <summary>
        /// Name of the Module it must be unique
        /// </summary>
        public string Name
        {
            get
            {
                return name;
            }
            protected set
            {
                name = value;
            }
        }

        /// <summary>
        /// Gets the full name of the Type of module
        /// </summary>
		public string TypeName
		{
			get
			{
				return typeName;
			}
			internal set
			{
				typeName = value;
			}
		}

        ///// <summary>
        ///// This flag is true when module is initialized
        ///// </summary>
        //public bool IsInitialized
        //{
        //    get
        //    {
        //        return isInitialized;
        //    }
        //    protected set
        //    {
        //        isInitialized = value;
        //    }
        //}

        /// <summary>
        /// Gets or sets the visibility of the module
        /// </summary>
        public virtual bool IsVisible
        {
            get
            {
                return isVisible;
            }
            set
            {
                foreach (ISmartpart sm in Smartparts)
                {
                    sm.IsVisible = value;
                }
                isVisible = value;
                if (VisibleChanged != null)
                {
                    VisibleChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets or sets the Enable flag for module
        /// </summary>
        public virtual bool IsEnabled
        {
            get
            {
                return isEnabled;
            }
            set
            {
                foreach (ISmartpart sm in Smartparts)
                {
                    sm.IsEnabled = value;
                }
                isEnabled = value;
                if (EnabledChanged != null)
                {
                    EnabledChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets the ResourceHandler
        /// </summary>
        public ResourceHandler Resources
        {
            get
            {
                return resources;
            }
        }

        /// <summary>
        /// Gets the Smartparts of the module
        /// </summary>
        public ISmartpart[] Smartparts
        {
            get
            {
                return Array.FindAll<ISmartpart>(host.Smartparts.Items, new Predicate<ISmartpart>(IsParentOf));
            }
        }

        /// <summary>
        /// Gets the Version of the module
        /// </summary>
        public System.Version Version
        {
            get
            {
                return version;
            }
        }

        /// <summary>
        /// Gets the FileVersion of the module
        /// </summary>
        public System.Version AssemblyVersion
        {
            get
            {
                return asmVersion;
            }
        }

        /// <summary>
        /// Gets the Icon of the module
        /// </summary>
        public Icon Icon
        {
            get
            {
                return icon;
            }
        }

        /// <summary>
        /// Unique key of persistable. The Name property of the Module is used default.
        /// </summary>
		public string PersistencyKey
		{
			get
			{
				return name;
			}
		}

        /// <summary>
        /// Gets the Configuration settings of the module
        /// </summary>
        public ApplicationSettingsBase Settings
        {
            get
            {
                return settings;
            }
        }

        /// <summary>
        /// Capability of asynchronous Loading and initializing
        /// </summary>
		public bool AsyncLoad
		{
			get
			{
				return isAsyncLoad;
			}
			protected set
			{
				isAsyncLoad = value;
			}
		}

		/// <summary>
		/// The parent IPersistable object of module
		/// </summary>
		public IPersistable ParentPersistable
		{
			get
			{
				return parentPersistable;
			}
			set
			{
				parentPersistable = value;
			}
		}

		/// <summary>
		/// Returns the module's configuration file as System.Configuration.Configuration
		/// </summary>
		public System.Configuration.Configuration Configuration
		{
			get
			{
				if (configuration == null)
				{
					string privatepath = System.Reflection.Assembly.GetAssembly(this.GetType()).Location;
					configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(privatepath);
				}
				return configuration;
			}
		}

        #endregion

        #region Public events

        /// <summary>
        /// VisibleChanged
        /// </summary>
        public event EventHandler VisibleChanged;
        /// <summary>
        /// EnabledChanged
        /// </summary>
        public event EventHandler EnabledChanged;

        #endregion

        #region Public methods

        ///// <summary>
        ///// Initialzes the module this method called by the ModuleLoader
        ///// </summary>
        //public abstract void Initialize();

        ///// <summary>
        ///// Terminatese the module this method called by the ModuleLoader
        ///// </summary>
        //public abstract void Terminate();

        /// <summary>
        /// Base pattern method of state saving
        /// </summary>
		public abstract void SavePersistency();

        /// <summary>
        /// Base pattern method of state loading
        /// </summary>
		public abstract void LoadPersistency();

		/// <summary>
		/// Returns true, if the module is the parent of the passed smartpart
		/// </summary>
		/// <param name="smartpart">ISmartpart smartpart</param>
		/// <returns>bool</returns>
		public bool IsParentOf(ISmartpart smartpart)
		{
			return smartpart.ParentModule == this;
		}

		/// <summary>
		/// Disposes the module
		/// </summary>
		public new virtual void Dispose()
		{
            base.Dispose();
			host = null;
			resources = null;
			version = null;
			if (icon != null)
			{
				icon.Dispose();
				icon = null;
			}
		}

        #endregion

        #region Private helper methods

        private void InitializeConfiguration(Assembly asm)
        {
            try
            {
                Configuration conf = ConfigurationManager.OpenExeConfiguration(asmPath);
				moduleProfile = (ModuleProfile)conf.Sections.Get("moduleProfile");
				
				ConfigurationSectionGroup csg = conf.GetSectionGroup("applicationSettings");
				if (csg != null)
				{
					ConfigurationSection settingsSection = GetPropertiesSection(csg.Sections);
					settings = (ApplicationSettingsBase)asm.CreateInstance(settingsSection.SectionInformation.Name);
				}
				else
				{
					settings = null;
				}
            }
            catch (Exception ex)
            {
				host.LogManager.WriteError(string.Format("Exception while initializing configuration - {0}", ex.ToString()), this, "ModuleLoader");
            }
        }

		private ConfigurationSection GetPropertiesSection(ConfigurationSectionCollection csc)
		{
			foreach (ConfigurationSection cs in csc)
			{
				if ((cs.ElementInformation.Type == typeof(ClientSettingsSection)) && cs.SectionInformation.Name.EndsWith("Properties.Settings"))
				{
					return cs;
				}
			}

			return null;
		}

        #endregion

	}
}
